package com.zhaorujie.rpc.core.remoting.netty.client;

import com.zhaorujie.rpc.core.remoting.invoker.RpcInvokerFactory;
import com.zhaorujie.rpc.core.remoting.params.RpcRequest;
import com.zhaorujie.rpc.core.serialize.RpcSerialize;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * @author 赵汝杰
 * @version v1.0
 * @description NettyClientConnect
 * @date 2024/3/11
 **/
public class NettyClientConnect extends NettyClient {

    private static volatile ConcurrentMap<String, NettyClientConnect> connectClientMap;
    private static final ConcurrentMap<String, Object> CONNECT_CLIENT_LOCK_MAP = new ConcurrentHashMap<>();

    /**
     * 获取客户端连接池，作用：减少客户端的创建
     * @param address 远程调用的地址
     * @param rpcSerialize rpc序列化
     * @param rpcReferenceBean rpc应用的bean对象
     * @return
     */
    public NettyClient getConnectPool(final String address, final RpcSerialize rpcSerialize, final RpcInvokerFactory rpcInvokerFactory) {
        // 双重判断
        if (connectClientMap == null) {
            synchronized (NettyClient.class) {
                if (connectClientMap == null) {
                    connectClientMap = new ConcurrentHashMap<>();
                }
            }
        }

        NettyClient connectClient = connectClientMap.get(address);
        if (connectClient !=null && connectClient.isValidate()) {
            return connectClient;
        }

        Object lock = CONNECT_CLIENT_LOCK_MAP.get(address);
        if (lock == null) {
            CONNECT_CLIENT_LOCK_MAP.putIfAbsent(address, new Object());
            lock = CONNECT_CLIENT_LOCK_MAP.get(address);
        }

        synchronized (lock) {
            connectClient = connectClientMap.get(address);
            if (connectClient != null && connectClient.isValidate()) {
                return connectClient;
            }

            if (connectClient != null) {
                connectClient.close();
                connectClientMap.remove(address);
            }
            NettyClientConnect nettyClientConnect = new NettyClientConnect();
            // 初始化客户端的连接对象
            nettyClientConnect.init(address, rpcSerialize, rpcInvokerFactory);
            // 关联当前的地址和客户端连接的关系
            connectClientMap.put(address, nettyClientConnect);
            return nettyClientConnect;
        }
    }

    @Override
    public void send(RpcRequest rpcRequest, String address, RpcSerialize rpcSerialize, RpcInvokerFactory rpcInvokerFactory) {
        NettyClient connectPool = getConnectPool(address, rpcSerialize, rpcInvokerFactory);
        connectPool.getChannel().writeAndFlush(rpcRequest);
    }

    /**
     * 服务销毁是需要把客户端的channel关闭
     */
    public static void destroy() {
        if (connectClientMap != null) {
            connectClientMap.forEach((address, client) -> client.close());
        }
    }
}
